//
// Created by Administrator on 2017/8/3.
//

#include "MatchImage.h"
#include <string>

using namespace std;

namespace img {
    Prt<MatchImage> MatchImage::mInterface;

    uint32_t MatchImage::overlapArea(Prt<Image> &src, Prt<Image> &dic) {
        if (src->getFormat() != src->getFormat())
            return 0;

        uint32_t ret = 0;
        if (IMAGE_FORMAT_RGBA_8888 == src->getFormat()) {
            uint32_t *srcData32 = (uint32_t *) src->getData();
            uint32_t *endData32 = srcData32 + src->getWidth() * src->getHeight();
            uint32_t *dicData32 = (uint32_t *) dic->getData();
            for (; srcData32 < endData32; ++srcData32, ++dicData32) {
                ret += (*dicData32 == *srcData32);
            }
            return ret;
        } else if (IMAGE_FORMAT_A_8 == src->getFormat()) {
            uint8_t *srcData8 = (uint8_t *) src->getData();
            uint8_t *endData8 = srcData8 + src->getWidth() * src->getHeight();
            uint8_t *dicData8 = (uint8_t *) dic->getData();
            for (; srcData8 < endData8; ++srcData8, ++dicData8) {
                ret += (*dicData8 == *srcData8);
            }
            return ret;
        }
        return 0;
    }


    Prt<MatchImage> &MatchImage::get() {
        if (MatchImage::mInterface.isNull())
            MatchImage::mInterface = new MatchImage();
        return MatchImage::mInterface;
    }

    void MatchImage::setInterface(const Prt<MatchImage> &mInterface) {
        MatchImage::mInterface = mInterface;
    }

    uint64_t
    MatchImage::overlapGrid(Prt<Image> &src, Prt<Image> &dic, int gridCount, float matching) {
        if (src->getFormat() != src->getFormat())
            return 0;
        gridCount = 1 > gridCount ? 1 : (8 < gridCount ? 8 : gridCount);

        int width = src->getWidth();
        int height = src->getHeight();
        int count = gridCount * gridCount;
        float scaleX = (float) width / gridCount;
        float scaleY = (float) height / gridCount;
        int pX, pY;
        float pX1, pY1;

        uint32_t gridV[gridCount][gridCount];
        uint32_t gridC[gridCount][gridCount];
        int y, x;
        for (y = 0, pY = 0, pY1 = scaleY; y < gridCount; y++, pY = pY1, pY1 += scaleY) {
            for (x = 0, pX = 0, pX1 = scaleX; x < gridCount; x++, pX = pX1, pX1 += scaleX) {
                gridV[y][x] = 0;
                gridC[y][x] = ((int) (pY1 - pY)) * ((int) (pX1 - pX));
            }
        }

        uint32_t *memory = (uint32_t *) malloc((width + height) * sizeof(uint32_t));
        uint32_t *tabX = memory;
        uint32_t *endX = tabX + width;
        for (int x = 0; x < width; ++x, ++tabX) {
            *tabX = x / scaleX;
        }

        uint32_t *tabY = endX;
        uint32_t *endY = tabY + height;
        for (int y = 0; y < height; ++y, ++tabY) {
            *tabY = y / scaleY;
        }

        uint32_t *gv, *gc;
        if (IMAGE_FORMAT_RGBA_8888 == src->getFormat()) {
            uint32_t *srcData32 = (uint32_t *) src->getData();
            uint32_t *dicData32 = (uint32_t *) dic->getData();
            for (tabY = endY - height; tabY < endY; ++tabY) {
                gv = ((uint32_t *) gridV) + *tabY * gridCount;
                for (tabX = endX - width; tabX < endX; ++tabX, ++srcData32, ++dicData32) {
                    *(gv + *tabX) += (*dicData32 == *srcData32);
                }
                --srcData32;
                --dicData32;
            }
        } else if (IMAGE_FORMAT_A_8 == src->getFormat()) {
            uint8_t *srcData = (uint8_t *) src->getData();
            uint8_t *dicData = (uint8_t *) dic->getData();
            for (tabY = endY - height; tabY < endY; ++tabY) {
                gv = ((uint32_t *) gridV) + *tabY * gridCount;
                for (tabX = endX - width; tabX < endX; ++tabX, ++srcData, ++dicData) {
                    *(gv + *tabX) += (*dicData == *srcData);
                }
                --srcData;
                --dicData;
            }
        }

        uint64_t ret = 0;
        for (y = 0, gv = (uint32_t *) gridV, gc = (uint32_t *) gridC; y < count; ++y, ++gv, ++gc) {
            ret |= (((float) *gv / *gc) >= matching) << y;
        }

        free(memory);
        return ret;
    }

}